<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>copy/clone，对不同数据对象，是否是深拷贝的测试</title>
    <style>
      body {
        margin: 0;
        overflow: hidden;
        /* 隐藏body窗口区域滚动条 */
      }
    </style>
    <!--引入three.js三维引擎-->
    <!-- <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script> -->
    <!-- <script src="http://www.yanhuangxueyuan.com/threejs/build/three.js"></script> -->
    <!-- Three.js-master 包示例中的用法 examples/js/controls/OrbitControls.js  版本要匹配-->
    <script type="importmap">
      {
        "imports": {
          "three": "../../node_modules/three/build/three.module.js",
          "three/addons/": "../../node_modules/three/examples/jsm/"
        }
      }
    </script>
  </head>
  <body>
    <script type="module">
      import {
        RAFTime,
        sphereMesh,
        cylinderMesh,
        v2ToV3,
      } from "../../util/index.js";

      import * as THREE from "three";
      import { OrbitControls } from "three/addons/controls/OrbitControls.js";
      import Stats from "three/addons/libs/stats.module.js";
      import { GUI } from "three/addons/libs/lil-gui.module.min.js";

      /**
       * 创建场景对象Scene
       */
      var scene = new THREE.Scene();
      // 创建一个组表示所有的雨滴
      var group = new THREE.Group();

      // 本章核心代码----------------------------测试copy/clone，对向量、几何体、材质、模型的复制拷贝效果
      // var v1 = new THREE.Vector3(1, 2, 3);
      // var v2 = new THREE.Vector3(3, 2, 1);
      // // -------------------------------------------向量的copy是深拷贝
      // v2.copy(v1);
      // v1.x = 5;
      // console.log("v1-copy----", v1);
      // console.log("v2-copy----", v2);

      // var v1 = new THREE.Vector3(1, 2, 3);
      // var v2;
      // // -------------------------------------------向量的clone是深拷贝
      // v2 = v1.clone();
      // v1.x = 5;
      // console.log("v1-clone----", v1);
      // console.log("v2-clone----", v2);

      // var geometry1 = new THREE.BoxGeometry(100, 100, 100); //矩形平面
      // var geometry2 = new THREE.BoxGeometry(10, 10, 10); //矩形平面
      // // ---------------------------------------------------------------几何体的copy是深拷贝
      // geometry2.copy(geometry1);
      // //类型数组创建顶点颜色color数据
      // var colors = new Float32Array([
      //   1,
      //   0,
      //   0, //顶点1颜色
      //   0,
      //   1,
      //   0, //顶点2颜色
      //   0,
      //   0,
      //   1, //顶点3颜色

      //   1,
      //   1,
      //   0, //顶点4颜色
      //   0,
      //   1,
      //   1, //顶点5颜色
      //   1,
      //   0,
      //   1, //顶点6颜色
      // ]);
      // geometry1.attributes.color = new THREE.BufferAttribute(colors, 3);
      // console.log("geometry1-copy----", geometry1);
      // console.log("geometry2-copy----", geometry2);

      // var geometry1 = new THREE.BoxGeometry(100, 100, 100); //矩形平面
      // var geometry2;
      // // ---------------------------------------------------------------几何体的clone是深拷贝
      // geometry2 = geometry1.clone();
      // //类型数组创建顶点颜色color数据
      // var colors = new Float32Array([
      //   1,
      //   0,
      //   0, //顶点1颜色
      //   0,
      //   1,
      //   0, //顶点2颜色
      //   0,
      //   0,
      //   1, //顶点3颜色

      //   1,
      //   1,
      //   0, //顶点4颜色
      //   0,
      //   1,
      //   1, //顶点5颜色
      //   1,
      //   0,
      //   1, //顶点6颜色
      // ]);
      // geometry1.attributes.color = new THREE.BufferAttribute(colors, 3);
      // console.log("geometry1-clone----", geometry1);
      // console.log("geometry2-clone----", geometry2);

      // let material1 = new THREE.MeshLambertMaterial({
      //   color: "#ff0000",
      //   side: THREE.FrontSide,
      // });
      // let material2 = new THREE.MeshLambertMaterial({
      //   color: "#0000ff",
      //   side: THREE.BackSide,
      // });
      // // ---------------------------------------------------------------材质的copy是深拷贝
      // material2.copy(material1);
      // material1.color.set("#00ff00");
      // console.log("material1-copy----", material1);
      // console.log("material2-copy----", material2);

      // let material1 = new THREE.MeshLambertMaterial({
      //   color: "#ff0000",
      //   side: THREE.FrontSide,
      // });
      // let material2;
      // // ---------------------------------------------------------------材质的clone是深拷贝
      // material2 = material1.clone();
      // material1.color.set("#00ff00");
      // console.log("material1-clone----", material1);
      // console.log("material2-clone----", material2);

      // let geometry1 = new THREE.BoxGeometry(100, 100, 100); //矩形平面
      // let material1 = new THREE.MeshLambertMaterial({
      //   color: "#ff0000",
      //   side: THREE.FrontSide,
      // });
      // let mesh1 = new THREE.Mesh(geometry1, material1);
      // mesh1.position.set(100, 100, 0);
      // scene.add(mesh1);
      // let mesh2 = new THREE.Mesh();
      // mesh2.copy(mesh1);
      // // ----------------------------------------------------------模型的copy对于potion属性是深拷贝
      // mesh1.position.set(0, 100, 100);
      // // ----------------------------------------------------------模型的copy对于material属性是浅拷贝
      // mesh1.material.color.set("#00ff00");
      // // material1.color.set("#0000ff");
      // scene.add(mesh2);
      // // ----------------------------------------------------------模型的copy对于geometry属性是浅拷贝
      // mesh1.geometry.rotateX(1);

      let geometry1 = new THREE.BoxGeometry(100, 100, 100); //矩形平面
      let material1 = new THREE.MeshLambertMaterial({
        color: "#ff0000",
        side: THREE.FrontSide,
      });
      let mesh1 = new THREE.Mesh(geometry1, material1);
      mesh1.position.set(100, 100, 0);
      scene.add(mesh1);
      let mesh2;
      mesh2 = mesh1.clone();
      // ----------------------------------------------------------模型的clone对于potion属性是深拷贝
      mesh1.position.set(0, 100, 100);
      // ----------------------------------------------------------模型的clone对于material属性是浅拷贝
      mesh1.material.color.set("#00ff00");
      // material1.color.set("#0000ff");
      scene.add(mesh2);
      // ----------------------------------------------------------模型的clone对于geometry属性是浅拷贝
      // mesh1.geometry.rotateX(1);
      geometry1.rotateX(1);

      /**
       * 创建一个草地地面
       */
      var geometry = new THREE.PlaneGeometry(1000, 1000); //矩形平面
      // 加载草地纹理贴图
      var texture = new THREE.TextureLoader().load(
        "../../public/images/threejs65tree.png"
      );
      // 设置纹理的重复模式
      texture.wrapS = THREE.RepeatWrapping;
      texture.wrapT = THREE.RepeatWrapping;
      // uv两个方向纹理重复数量
      texture.repeat.set(10, 10);
      var material = new THREE.MeshLambertMaterial({
        // color: 0x777700,
        map: texture,
        transparent: true,
      });
      var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
      scene.add(mesh); //网格模型添加到场景中
      mesh.rotateX(-Math.PI / 2);
      mesh.position.y = 1; //适当偏移，不与地面重合

      // 添加一个辅助网格地面
      const gridHelper = new THREE.GridHelper(1000, 1000, 0x004444, 0x004444);
      scene.add(gridHelper);

      /**
       * 辅助坐标系 参数250表示坐标系大小，可以根据场景大小去设置
       */
      var axesHelper = new THREE.AxesHelper(1000);
      scene.add(axesHelper);

      // 平行光
      var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
      // 平行光辅助对象
      const directionalLightHelper = new THREE.DirectionalLightHelper(
        directionalLight,
        10
      );
      scene.add(directionalLightHelper);
      // 设置光源位置
      directionalLight.position.set(60, 60, 60);
      scene.add(directionalLight);
      // 设置用于计算阴影的光源对象
      directionalLight.castShadow = true;
      // 设置计算阴影的区域，最好刚好紧密包围在对象周围
      // 计算阴影的区域过大：模糊  过小：看不到或显示不完整
      directionalLight.shadow.camera.near = 0.5;
      directionalLight.shadow.camera.far = 300;
      directionalLight.shadow.camera.left = -100;
      directionalLight.shadow.camera.right = 100;
      directionalLight.shadow.camera.top = 200;
      directionalLight.shadow.camera.bottom = -200;
      // 设置mapSize属性可以使阴影更清晰，不那么模糊
      directionalLight.shadow.mapSize.set(1024, 1024);
      // console.log(directionalLight.shadow.camera);

      //环境光
      var ambient = new THREE.AmbientLight(0x050505);
      scene.add(ambient);

      /**
       * 相机设置
       */
      var width = window.innerWidth; //窗口宽度
      var height = window.innerHeight; //窗口高度
      var k = width / height; //窗口宽高比
      // var s = 1; //三维场景显示范围控制系数，系数越大，显示的范围越大
      // //创建相机对象
      // var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 100);
      // ---------------------------------------目8.9 环境贴图，使用PerspectiveCamera比OrthographicCamera更真正，人眼视角
      var camera = new THREE.PerspectiveCamera(60, k, 1, 2000);
      camera.position.set(292, 109, 268); //设置相机位置
      camera.lookAt(scene.position); //设置相机方向(指向的场景对象)

      /**
       * 创建渲染器对象
       */
      var renderer = new THREE.WebGLRenderer({
        alpha: true,
      });
      renderer.setSize(width, height); //设置渲染区域尺寸
      renderer.setClearAlpha(0); // 设置背景透明度
      renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色，背景透明度

      // 设置渲染器，允许光源阴影渲染
      renderer.shadowMap.enabled = true;
      document.body.appendChild(renderer.domElement); //body元素中插入canvas对象

      // ------------------------------------------------------------------------------------------渲染性能工具stats.js
      const stats = new Stats();
      stats.setMode(1);
      document.body.appendChild(stats.domElement);

      // ------------------------------------------------------------------------------------------交互界面工具gui.js
      const gui = new GUI();
      // gui.close();
      //改变交互界面style属性
      gui.domElement.style.right = "0px";
      gui.domElement.style.width = "300px";

      // 界面分组
      const directionalLightFolder = gui.addFolder("平行光父文件夹");

      // directionalLightFolder.close();

      directionalLightFolder
        .addColor(directionalLight, "color")
        .name("平行光颜色")
        .step(0.1)
        .onChange(function (value) {
          directionalLight.color.set(value);
        });

      const directionalLightSubFolder =
        directionalLightFolder.addFolder("平行光子文件夹");

      directionalLightSubFolder
        .add(directionalLight, "intensity", 0, 10)
        .name("平行光强度")
        .step(0.1);

      const rotateAngle = gui.addFolder("物体旋转角度");
      rotateAngle.add(mesh2.rotation, "x", 0, 2 * Math.PI);

      // 递归函数,每1/60秒左右,调用一次自己
      const render = RAFTime((t) => {
        stats.update();
        // mesh1.geometry.rotateX(0.1);
        renderer.render(scene, camera); //执行渲染操作
      });

      // 启动渲染---requestAnimationFrame周期性的渲染
      render();

      // 创建，轨迹控件---实现旋转/平移/缩放
      var controls = new OrbitControls(camera, renderer.domElement);
      // 监听鼠标、键盘事件
      // controls.addEventListener("change");

      // 窗口大小变化后，设置画布 => 设置相机参数 => 更新投影矩阵
      window.onresize = function () {
        // 重置渲染器输出画布canvas尺寸
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
        camera.aspect = window.innerWidth / window.innerHeight;
        // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
        // 但是不会每渲染一帧，就通过相机的属性计算投影矩阵(节约计算资源)
        // 如果相机的一些属性发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
        camera.updateProjectionMatrix();
      };
    </script>
  </body>
</html>
